package com.czk.durant.springframework.beans.factory.support;

import cn.hutool.core.bean.BeanUtil;
import com.czk.durant.springframework.beans.factory.config.BeanDefinition;
import com.czk.durant.springframework.beans.PropertyValue;
import com.czk.durant.springframework.beans.PropertyValues;
import com.czk.durant.springframework.beans.factory.config.BeanReference;

import java.lang.reflect.Constructor;

/**
 * 实例化时根据策略进行
 *
 * @Author:ChenZhangKun
 * @Date: 2021/6/9 14:57
 */
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {
    /**
     * 定制实例化策略
     * 默认以cglib的方式进行实例化，如果需要请传入的实例化策略
     */
    private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();

    @Override
    protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) {
        Object bean = null;
        try {
            bean = createBeanInstance(beanName, beanDefinition, args);
            applyPropertyValues(beanName, bean, beanDefinition);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        if (bean != null) {
            // 加入容器
            addSingleton(beanName, bean);
        } else {
            throw new RuntimeException("创建实例出错");
        }
        return bean;
    }

    /**
     * 进行对象的属性填充
     *
     * @param beanName
     * @param bean
     * @param beanDefinition
     */
    protected void applyPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) {
        // 拿到依赖的集合
        PropertyValues propertyValues = beanDefinition.getPropertyValues();
        // 遍历
        for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {
            // 拿到名称
            String name = propertyValue.getName();
            // 拿到属性
            Object value = propertyValue.getValue();
            if (value instanceof BeanReference) {
                BeanReference beanReference = (BeanReference) value;
                value = getBean(beanReference.getBeanName());
            }
            BeanUtil.setFieldValue(bean, name, value);
        }
    }

    /**
     * 创建对象实例
     *
     * @param beanName
     * @param beanDefinition
     * @param args
     * @return
     */
    protected Object createBeanInstance(String beanName, BeanDefinition beanDefinition, Object[] args) {
        // 拿到class
        Class clazz = beanDefinition.getBeanClass();
        // 声明外面构造器
        Constructor constructor = null;
        // 拿到声明的构造器
        Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
        // 遍历
        for (Constructor declaredConstructor : declaredConstructors) {
            // 只判断了数量没有判断类型
            if (args != null && declaredConstructor.getParameterTypes().length == args.length) {
                constructor = declaredConstructor;
                break;
            }
        }
        // 实例化
        return instantiationStrategy.instantiate(beanDefinition, beanName, constructor, args);
    }

    /**
     * 便于获取
     *
     * @return
     */
    public InstantiationStrategy getInstantiationStrategy() {
        return instantiationStrategy;
    }

    /**
     * 便于覆盖
     *
     * @param instantiationStrategy
     */
    public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy) {
        this.instantiationStrategy = instantiationStrategy;
    }
}
